#include "dbusSignalmodel.hpp"
#include <qvariant.h>
#include <qmetatype.h>
#include <QtDBus>
#include <qimage.h>
#define DBUS_TYPE_STRUCT QMetaType::User+2001
#define DBUS_TYPE_DICT   QMetaType::User+2002
#define DBUS_TYPE_ARRAR  QMetaType::User+2003
#define LEVEL_ROOT 0
#define LEVEL_TOP 1

const auto mimeType = QStringLiteral("application/x-qabstractitemmodeldatalist");

DbusSignalModel::DbusSignalModel(QObject *parent) : QAbstractItemModel(parent)
{
    root = new DbusTestModelItem();
    m_ColumnsId<<0;
    m_ColumnsId<<1;
    m_ColumnsId<<2;
    m_ColumnsId<<3;
    m_ColumnsId<<9;
    m_ColumnsId<<4;
    m_ColumnsId<<5;
    m_ColumnsId<<6;
    m_ColumnsId<<7;
    m_ColumnsId<<8;
}

DbusSignalModel::~DbusSignalModel()
{
    qDeleteAll(m_dbusSignals);
    delete root;
}

void DbusSignalModel::connectAll()
{
    for(DbusTestModelItem *item : root->children)
    {
        connectItem(item);
    }
}

void DbusSignalModel::disconnectAll()
{
    for(DbusSignalItem *item : m_dbusSignals)
    {
        disconnect (item,&DbusSignalItem::signalCall,this,&DbusSignalModel::signalCall);
    }
    qDeleteAll(m_dbusSignals);
    m_dbusSignals.clear ();;
}

void DbusSignalModel::connectItem(DbusTestModelItem *item)
{


    if(item->skip ())
    {
        for(DbusSignalItem* it:m_dbusSignals)
        {
            if(*it ==item)
            {

                disconnect (it,&DbusSignalItem::signalCall,this,&DbusSignalModel::signalCall);
                it->deleteLater ();
                m_dbusSignals.removeOne (it);
                break;
            }
        }
    }else
    {
        for(DbusSignalItem* it:m_dbusSignals)
        {
            if(*it ==item)
            {
                return;
            }
        }
        DbusSignalItem *it = new DbusSignalItem(item);
        connect (it,&DbusSignalItem::signalCall,this,&DbusSignalModel::signalCall);
        m_dbusSignals.append (it);
    }
}

QVector<DbusTestModelItem *> DbusSignalModel::getItemList()
{
    return root->children;
}

DbusTestModelItem *DbusSignalModel::getItem(const QModelIndex &index)
{
    DbusTestModelItem *item = static_cast<DbusTestModelItem *>(index.internalPointer());
    return item;
}

void DbusSignalModel::importXML(QString context)
{
    disconnectAll ();
    qDeleteAll(root->children);
    root->children.clear ();
    beginResetModel ();
    root->setContext (context.toLatin1 ());
    endResetModel ();
    connectAll ();
}
QString DbusSignalModel::exportXML()
{
    QString str = root->toContext();
    return str;
}

void DbusSignalModel::append(DbusTestModelItem *item,const QModelIndex &index)
{
    const int position = root->children.count ();
    for(DbusTestModelItem *var : root->children)
    {
        if(var->m_data.mBus == item->m_data.mBus
                && var->m_data.mService == item->m_data.mService
                && var->m_data.mPath == item->m_data.mPath
                && var->m_data.mInterface == item->m_data.mInterface
                && var->m_data.mTypeSig == item->m_data.mTypeSig)
        {
            return;
        }
    }
    beginInsertRows(index, position, position);
    root->children.append (item);
    endInsertRows();
    connectItem (item);
}
void DbusSignalModel::insertItem(int position,DbusTestModelItem *item,const QModelIndex &index)
{
    beginInsertRows(index, position, position);
    root->children.insert (position,item);
    endInsertRows();
    connectItem (item);
}

bool DbusSignalModel::isSkip(const QModelIndex &index) const
{
    DbusTestModelItem *item = static_cast<DbusTestModelItem *>(index.internalPointer());
    if (!item)
    {
        return true;
    }
    return item->m_skip;
}
void DbusSignalModel::setSkip(const QModelIndex &index, bool isSkip)
{
    DbusTestModelItem *item = static_cast<DbusTestModelItem *>(index.internalPointer());
    if (!item)
        return;
    if(item->m_skip !=  isSkip)
    {
        connectItem (item);
    }
    item->m_skip =  isSkip;
}

QModelIndexList DbusSignalModel::getResultIndex(DbusTestModelItem *item)
{
    QModelIndexList list;
    for(int i=0;i<root->children.count ();i++)
    {
        if(root->children.at (i) == item)
        {
            int coulmnID = getColumnIndex(4);
            list<<index(i,coulmnID,QModelIndex());
            coulmnID = getColumnIndex(9);
            list<<index(i,coulmnID,QModelIndex());
        }
    }
    return list;
}
QModelIndex DbusSignalModel::index(int row, int column, const QModelIndex &parent) const
{
    if(!this->hasIndex (row,column,parent))
    {
        return QModelIndex();
    }
    DbusTestModelItem *parentItem = Q_NULLPTR;
    if(!parent.isValid ())
    {
        parentItem = root;
        if(parentItem->children.count ()>row)
        {
            return createIndex(row, column, parentItem->children.at(row));
        }else
        {
            return QModelIndex();;
        }
    }else
    {
        parentItem = static_cast<DbusTestModelItem *>(parent.internalPointer());
        if(parentItem->children.count ()>row)
        {
            return createIndex(row, column, parentItem->children.at(row));
        }else
        {
            return QModelIndex();;
        }
    }
}

QModelIndex DbusSignalModel::parent(const QModelIndex &child) const
{
    return QModelIndex();
}


int DbusSignalModel::rowCount(const QModelIndex &parent) const
{
    return root->children.count ();
}

int DbusSignalModel::columnCount(const QModelIndex &parent) const
{
     return m_ColumnsId.count ();
}

QVariant DbusSignalModel::data(const QModelIndex &index, int role) const
{
     QString str;
     bool isFrish = true;
     int coulmnID = getColumnId (index.column ());
    const DbusTestModelItem *item = static_cast<DbusTestModelItem *>(index.internalPointer());
    if (!item)
        return QVariant();
    if (role == Qt::CheckStateRole)
    {
        if(coulmnID==0)
        {
            return item->m_skip?Qt::Unchecked: Qt::Checked ;
        }
        return QVariant();
    }
    if (role == Qt::DecorationRole)
    {
        QVariant v;
        v.setValue(v);
        return v;
    }
    if (role == Qt::CheckStateRole)
    {
        return item->m_skip?Qt::Unchecked: Qt::Checked ;
    }
    if (role != Qt::DisplayRole)
        return QVariant();
    switch (coulmnID) {
    case 0:
        return QVariant();
        break;
    case 1:
        switch (item->m_data.type) {
        case MethodItem:
            return QLatin1String("Method");
            break;
        case SignalItem:
            return QLatin1String("Signal");
            break;
        case PropertyItemReadwrite:
        case PropertyItemRead:
        case PropertyItemWrite:
            if(item->dbusArgs.count ()>0)
            {
                return QLatin1String("SetProperty");
            }else
            {
                return QLatin1String("GetProperty");
            }
            break;
        default:
            break;
        }
        return QVariant();
        break;
    case 2:
        return item->m_data.mName;
        break;
    case 3:
        str = "";
        foreach (QString var, item->m_data.argTypes) {
            str.append (var);
        }
        return str;
        break;
    case 4:
        return QVariant(item->result());
        break;
    case 5:
        return item->m_data.mBus;
        break;
    case 6:
        return item->m_data.mService;
        break;
    case 7:
        return item->m_data.mPath;
        break;
    case 8:
        return item->m_data.mInterface;
        break;
    case 9:
        if(item->m_finshtime>0)
        {
            return QDateTime::fromMSecsSinceEpoch (item->m_finshtime).toString("hh:mm:ss.zzz");
        }
        break;
        break;
    default:
        break;
    }
    return QVariant();
}
bool DbusSignalModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (role == Qt::CheckStateRole)
    {

        DbusTestModelItem *item = static_cast<DbusTestModelItem *>(index.internalPointer());
        if(item!=Q_NULLPTR)
        {
            if(value.toInt () == Qt::Checked)
            {
                if(item->m_skip !=false)
                {
                    item->m_skip =false;
                    connectItem (item);
                }
            }
            else
            {
                if(item->m_skip !=true)
                {
                    item->m_skip =true;
                    connectItem (item);
                }
            }
            return true;
        }
    }
}
bool DbusSignalModel::insertRows(int row, int count, const QModelIndex &parent)
{
    return QAbstractItemModel::insertRows (row,count,parent);
}

bool DbusSignalModel::removeRows(int row, int count, const QModelIndex &parent)
{
    beginRemoveRows(parent, row, row);
    DbusTestModelItem *item = root->children.at (row);
    root->children.removeAt (row);
    delete item;
    endRemoveRows();
    return true;
}

bool DbusSignalModel::moveRows(const QModelIndex &sourceParent, int srcRow, int count, const QModelIndex &destinationParent, int dstRow)
{
    if (srcRow == dstRow
        || srcRow < 0 || srcRow >= root->children.count()
        || dstRow < 0 || dstRow > root->children.count())
    {
        return false;
    }
    if(srcRow<dstRow)
    {
        if (!beginMoveRows(QModelIndex(), srcRow, srcRow, QModelIndex(), dstRow+1))
        {
            return false;
        }
    }else
    {
        if (!beginMoveRows(QModelIndex(), srcRow, srcRow, QModelIndex(), dstRow))
        {
            return false;
        }
    }
    if(dstRow>=root->children.count ())
    {
        dstRow = root->children.count ()-1;
    }else if(dstRow<0)
    {
        dstRow = 0;
    }
    root->children.move (srcRow,dstRow);
    endMoveRows ();
    return true;
}

Qt::ItemFlags DbusSignalModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return QAbstractItemModel::flags(index);
    if(index.column ()==0)
    {
        Qt::ItemFlags flags =  Qt::ItemIsEditable | Qt::ItemIsUserCheckable | QAbstractItemModel::flags(index);;
        return flags;
    }

    return QAbstractItemModel::flags (index);
}

QVariant DbusSignalModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
    {
        int columnID = getColumnId (section);
        return getHeader (columnID);
    }
    return QVariant();
}

bool DbusSignalModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild)
{
    return false;
}

int DbusSignalModel::getColumnId(int index) const
{
    if(m_ColumnsId.count ()>index)
    {
        return m_ColumnsId.at (index);
    }
    return 0;
}

int DbusSignalModel::getColumnIndex(int id) const
{
    return m_ColumnsId.indexOf (id);
}


